package com.zhaokuner.pm.common.utils;

import com.alibaba.fastjson.JSON;
import com.zhaokuner.pm.model.common.BaseList;
import com.zhaokuner.pm.model.common.BaseResp;
import com.zhaokuner.pm.model.common.BaseRespBean;
import com.zhaokuner.pm.model.common.RespStatus;
import com.zhaokuner.pm.model.es.EsBaseDoc;
import com.zhaokuner.pm.model.es.EsBaseList;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseListener;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

/**
 * 类描述:RestClientUtil
 *
 * @author 赵希坤 zhaoxikun
 * @date 2020/8/21 18:02
 */
@Log4j2
@Component
public class RestClientUtil {

    private static RestClient restClient;

    @Autowired
    public void setRestClient(RestClient restClient) {
        RestClientUtil.restClient = restClient;
    }

    /**
     * 索引
     */
    private static String indexName;

    @Value("${elasticsearch.index}")
    public void setIndexName(String indexName) {
        RestClientUtil.indexName = indexName;
    }

    public static void test(SearchSourceBuilder searchSourceBuilder) {
        String endpoint = "/" + indexName + "/_search";
        String jsonEntity = searchSourceBuilder.toString();
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost("http://es.zhaokuner.com" + endpoint);
        StringEntity entity = new StringEntity(jsonEntity, "UTF-8");
        httpPost.setHeader("Content-Type", "application/json; charset=UTF-8");
        httpPost.setEntity(entity);
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpPost);
        } catch (IOException e) {
            e.printStackTrace();
        }
        byte[] byteStr = new byte[(int) response.getEntity().getContentLength()];
        try {
            response.getEntity().getContent().read(byteStr);
            String str = new String(byteStr);
            System.out.println(str);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 方法描述：查询里边
     *
     * @param queryBuilder 查询条件
     * @param pageIndex    请求页码
     * @param pageSize     请求条数
     * @param sortList     排序
     * @param clazz        返回结构
     * @return com.zhaokuner.pm.model.common.BaseList<T>
     * @date 日期：2020/8/23 时间：12:19
     * @author zhaokuner
     */
    public static <T> BaseList<T> list(QueryBuilder queryBuilder, int pageIndex, int pageSize, List<SortBuilder<?>> sortList, Class<T> clazz) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder
                .query(queryBuilder)
                .timeout(new TimeValue(60, TimeUnit.SECONDS))
                .from((pageIndex - 1) * pageSize)
                .size(pageSize);
        if (null != sortList) {
            for (SortBuilder<?> sortBuilder : sortList) {
                searchSourceBuilder.sort(sortBuilder);
            }
        }
        String endpoint = "/" + indexName + "/_search";
        String jsonEntity = searchSourceBuilder.toString();
        Request request = new Request("GET", endpoint);
        request.setJsonEntity(jsonEntity);
        BaseList<EsBaseList.EsBaseListDoc> baseListDocBaseList = list(request);
        BaseList<T> baseList = new BaseList<>();
        baseList.initPageInfo(baseListDocBaseList);
        if (baseListDocBaseList.isSuccess() && baseListDocBaseList.getTotalRows() > 0) {
            baseListDocBaseList.getList().forEach(a -> baseList.addListItem(a.get_source().toJavaObject(clazz)));
        }
        return baseList.putBaseResp(baseListDocBaseList);
    }

    /**
     * 方法描述： 请求类别
     *
     * @param request 请求
     * @return com.zhaokuner.pm.model.common.BaseList<com.zhaokuner.pm.model.es.EsBaseList.EsBaseListDoc>
     * @author zhaokuner
     * @date 日期：2020/8/23 时间：12:22
     */
    private static BaseList<EsBaseList.EsBaseListDoc> list(Request request) {
        BaseRespBean<String> brb = performRequest(request);
        BaseList<EsBaseList.EsBaseListDoc> baseList = new BaseList<>();
        if (brb.isSuccess() && StringUtils.isNotBlank(brb.getBean())) {
            EsBaseList esBaseListDoc = JSON.parseObject(brb.getBean(), EsBaseList.class);
            baseList.setTotalRows(esBaseListDoc.getHits().getTotal().getValue());
            baseList.setList(esBaseListDoc.getHits().getHits());
            baseList.success();
            return baseList;
        }
        return baseList.putBaseResp(brb);
    }

    /**
     * 方法描述：根据es _id获取数据
     *
     * @param id    es _id
     * @param clazz 返回的数据
     * @return com.zhaokuner.pm.model.common.BaseRespBean<T>
     * @author zhaokuner
     * @date 日期：2020/8/23 时间：12:23
     */
    public static <T> BaseRespBean<T> getById(String id, Class<T> clazz) {
        String endpoint = "/" + indexName + "/_doc/" + id;
        Request request = new Request("GET", endpoint);
        return get(request, clazz);
    }

    /**
     * 方法描述：获取单个
     *
     * @param request 请求
     * @param clazz   返回类
     * @return com.zhaokuner.pm.model.common.BaseRespBean<T>
     * @author 赵希坤
     * @date 日期：2020/8/23 时间：12:24
     */
    private static <T> BaseRespBean<T> get(Request request, Class<T> clazz) {
        BaseRespBean<String> brb = performRequest(request);
        if (brb.isSuccess() && StringUtils.isNotBlank(brb.getBean())) {
            EsBaseDoc esBaseDoc = JSON.parseObject(brb.getBean(), EsBaseDoc.class);
            if (esBaseDoc.getFound()) {
                return BaseRespBean.newBeanSuccess(esBaseDoc.get_source().toJavaObject(clazz));
            }
        }
        return BaseRespBean.newBeanBaseResp(brb);
    }

    /**
     * 方法描述：添加
     *
     * @param id   添加   es _id
     * @param node 数据
     * @return com.zhaokuner.pm.model.common.BaseResp
     * @author 赵希坤
     * @date 日期：2020/8/23 时间：12:25
     */
    public static BaseResp create(String id, Object node) {
        String endpoint = "/" + indexName + "/_create/" + id;
        Request request = new Request("POST", endpoint);
        HttpEntity httpEntity = new StringEntity(JsonUtils.toJson(node), ContentType.APPLICATION_JSON);
        request.setEntity(httpEntity);
        return performRequest(request);
    }

    /**
     * 方法描述：更新
     *
     * @param id     es _id
     * @param params 参数
     * @return com.zhaokuner.pm.model.common.BaseResp
     * @author 赵希坤
     * @date 日期：2020/8/23 时间：12:25
     */
    public static BaseResp update(String id, Object params) {
        String endpoint = "/" + indexName + "/_update/" + id;
        Request request = new Request("POST", endpoint);
        HashMap<String, Object> doc = new HashMap<>(8);
        doc.put("doc", params);
        HttpEntity httpEntity = new StringEntity(JsonUtils.toJson(doc), ContentType.APPLICATION_JSON);
        request.setEntity(httpEntity);
        return performRequest(request);
    }

    /**
     * 方法描述：用script 更新
     * <p>
     * script例子
     * <p>
     * 更新数量:ctx._source.counter += params.count
     * <p>
     * 条件判断:if (ctx._source.tags.contains(params.tag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.tag)) }
     *
     * @param id     es的_id
     * @param script 使用script
     * @param params 待更新的参数
     * @return com.zhaokuner.pm.model.common.BaseResp
     * @author zhaokuner
     * @date 日期：2020/8/23 时间：12:06
     */
    public static BaseResp updateScript(String id, String script, Object params) {
        String endpoint = "/" + indexName + "/_update/" + id;
        Request request = new Request("POST", endpoint);
        HashMap<String, Object> scriptObj = new HashMap<>(8);
        scriptObj.put("lang", "painless");
        scriptObj.put("source", script);
        scriptObj.put("params", params);
        HashMap<String, Object> doc = new HashMap<>(8);
        doc.put("script", scriptObj);
        HttpEntity httpEntity = new StringEntity(JsonUtils.toJson(doc), ContentType.APPLICATION_JSON);
        request.setEntity(httpEntity);
        return performRequest(request);
    }

    /**
     * 方法描述： 删除
     *
     * @param id es _id
     * @return com.zhaokuner.pm.model.common.BaseResp
     * @author 赵希坤
     * @date 日期 2020/8/23 时间 12:31
     */
    public static BaseResp delete(String id) {
        String endpoint = "/" + indexName + "/_doc/" + id;
        Request request = new Request("DELETE", endpoint);
        return performRequest(request);
    }

    /**
     * 方法描述： 执行 request
     *
     * @param request es 请求
     * @return com.zhaokuner.pm.model.common.BaseRespBean<java.lang.String>
     * @author 赵希坤
     * @date 日期 2020/8/23 时间 12:32
     */
    public static BaseRespBean<String> performRequest(Request request) {
        BaseRespBean<String> baseResp = BaseRespBean.newBeanError();
        try {
            Response response = restClient.performRequest(request);
            if (HttpStatus.SC_BAD_REQUEST > response.getStatusLine().getStatusCode()) {
                String string = EntityUtils.toString(response.getEntity());
                baseResp.success(string);
            } else {
                baseResp.putStatus(RespStatus.REQUEST_FAILURE);
            }
        } catch (IOException e) {
            return baseResp.msg(e.getMessage());
        }

        return baseResp;
    }

    /**
     * 方法描述： 异步请求
     *
     * @param request   请求
     * @param onSuccess 成功时执行
     * @param onFailure 失败时执行
     * @return void
     * @author 赵希坤
     * @date 日期 2020/8/23 时间 12:33
     */
    public static void performRequestAsync(Request request, Consumer<BaseRespBean<String>> onSuccess, Consumer<Exception> onFailure) {
        restClient.performRequestAsync(request, new ResponseListener() {
            @Override
            public void onSuccess(Response response) {
                if (null == onSuccess) {
                    return;
                }
                BaseRespBean<String> baseResp = BaseRespBean.newBeanError();
                try {
                    if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
                        String string = EntityUtils.toString(response.getEntity());
                        baseResp.success(string);
                    } else {
                        baseResp.putStatus(RespStatus.REQUEST_FAILURE);
                    }
                } catch (IOException e) {
                    baseResp.msg(e.getMessage());
                }
                onSuccess.accept(baseResp);
            }

            @Override
            public void onFailure(Exception exception) {
                if (null == onFailure) {
                    return;
                }
                onFailure.accept(exception);
            }
        });
    }


}
